﻿/*
	Copyright (c) 第三界主 2014
	代码使用MIT协议发布
*/

#include <wayland-client.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <linux/input.h>

#include "WTK.h"

////
//////////////////////////////////////////////////////////////////////////
static void shm_format(LPVOID data, struct wl_shm *wl_shm, uint32_t format) {
	LPWAYLANDGLOBALS lpRegistry = (LPWAYLANDGLOBALS )data;
	lpRegistry->shm_formats |= (1 << format);
}

struct wl_shm_listener shm_listenter = {
	shm_format
};

void registry_global(LPVOID data, HREGISTRY registry, uint32_t id, const char *interface, uint32_t version)
{
	LPWAYLANDGLOBALS lpRegistry = (LPWAYLANDGLOBALS )data;
	if (strcmp(interface, "wl_compositor") == 0)
	{
		lpRegistry->s_compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 1);
	}
	else if (strcmp(interface, "wl_shell") == 0)
	{
		lpRegistry->s_shell = wl_registry_bind(registry, id, &wl_shell_interface, 1);
	}
	else if (strcmp(interface, "wl_shm") == 0)
	{
		lpRegistry->s_shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
	}
	else if (strcmp(interface, "wl_seat") == 0)
	{
		lpRegistry->s_seat = wl_registry_bind(registry, id, &wl_seat_interface, 1);
		lpRegistry->s_pointer = wl_seat_get_pointer(lpRegistry->s_seat);
		lpRegistry->s_keyboard = wl_seat_get_keyboard(lpRegistry->s_seat);
	}
}

static void registry_global_remove(LPVOID data, HREGISTRY registry, uint32_t name){
}

static struct wl_registry_listener registry_listener = { 
	.global = registry_global,
	.global_remove = registry_global_remove
};

BOOL InitWayland()
{
	LPWAYLANDGLOBALS lpGlobals = (LPWAYLANDGLOBALS)malloc(sizeof());
	memset(lpGlobals, 0, sizeof(*lpGlobals));

	lpGlobals->s_display = wl_display_connect(NULL);
	if (NULL == lpGlobals->s_display)
	{
		return WL_FALSE;
	}

	wl_display_set_user_data(lpGlobals->s_display, lpGlobals);

	lpGlobals->s_registry = wl_display_get_registry(lpGlobals->s_display);

	/* wayland的API是异步的，需要给registry设置回掉函数 */
	wl_registry_add_listener(lpGlobals->s_registry, &registry_listener, lpGlobals);
	wl_display_roundtrip(lpGlobals->s_display);

	wl_shm_add_listener(lpGlobals->s_shm, &shm_listenter, lpGlobals);
	wl_display_roundtrip(lpGlobals->s_display);
	return WL_TRUE;
}

// 
// void pointer_enter(void *data, HPOINTER wl_pointer, uint32_t serial, HSURFACE surface, 
// 	wl_fixed_t surface_x, wl_fixed_t surface_y)
// {
// 	//wlGetRegistry()->s_pointer_surface = surface;
// }
// 
// void pointer_leave(void *data, HPOINTER wl_pointer, uint32_t serial, HSURFACE surface)
// {
// 	//wlGetRegistry()->s_pointer_surface = NULL;
// }
// 
// void pointer_motion(void *data, HPOINTER wl_pointer, uint32_t time, 
// 	wl_fixed_t surface_x, wl_fixed_t surface_y)
// {
// 
// }
// 
// void pointer_button(void *data, HPOINTER wl_pointer, uint32_t serial, 
// 	uint32_t time, uint32_t button, uint32_t state)
// {
// // 	HSURFACE hSurface = wlGetRegistry()->s_pointer_surface;
// // 	if (hSurface != NULL)
// // 	{
// // 		wlCallPointerProc(hSurface, button, state, serial);
// // 	}
// }
// 
// void pointer_axis(void *data, struct wl_pointer *wl_pointer, 
// 	uint32_t time, uint32_t axis, wl_fixed_t value)
// {
// 
// }
// 
// struct wl_pointer_listener pointer_listener = {
// 	.enter = pointer_enter,
// 	.leave = pointer_leave,
// 	.motion = pointer_motion,
// 	.button = pointer_button,
// 	.axis = pointer_axis
// };
// 
// void keyboard_keymap(LPVOID data, HKEYBOARD wl_keyboard, uint32_t format, 
// 	int32_t fd, uint32_t size)
// {
// 
// }
// 
// void keyboard_enter(LPVOID data, HKEYBOARD wl_keyboard, uint32_t serial, 
// 	HSURFACE surface, struct wl_array *keys)
// {
// 	printf("keyboard focus.\n");
// }
// 
// void keyboard_leave(void *data, HKEYBOARD wl_keyboard, uint32_t serial, HSURFACE surface)
// {
// 
// }
// 
// void keyboard_key(void *data, HKEYBOARD wl_keyboard,
// 	uint32_t serial,
// 	uint32_t time,
// 	uint32_t key,
// 	uint32_t state)
// {
// 	if (KEY_F4 == key && WL_KEYBOARD_KEY_STATE_PRESSED == state)
// 	{
// 		exit(0);
// 	}
// }
// 
// void keyboard_modifiers(void *data,
// 	HKEYBOARD wl_keyboard,
// 	uint32_t serial,
// 	uint32_t mods_depressed,
// 	uint32_t mods_latched,
// 	uint32_t mods_locked,
// 	uint32_t group)
// {
// 
// }
// 
// struct wl_keyboard_listener keyboard_listener = {
// 	.keymap = keyboard_keymap, 
// 	.enter = keyboard_enter, 
// 	.leave = keyboard_leave, 
// 	.key = keyboard_key, 
// 	.modifiers = keyboard_modifiers
// };
// 
// static void handle_ping(LPVOID data, HSHELLSURFACE shell_surface, uint32_t serial)
// {
// 	wl_shell_surface_pong(shell_surface, serial);
// }
// 
// static void handle_configure(LPVOID data, HSHELLSURFACE shell_surface, 
// 	uint32_t edges, int32_t width, int32_t height)
// {
// 
// }
// 
// static void handle_popup_done(LPVOID data, HSHELLSURFACE shell_surface){
// 
// }
// 
// static const struct wl_shell_surface_listener shell_surface_listener = {
// 	.ping = handle_ping,
// 	.configure = handle_configure,
// 	.popup_done = handle_popup_done
// };
// 
// 
// 
// 
 
HSURFACE CreateSurface(const char* title, int width, int height)
{
 	/* wayland中，窗口被称作surface */
 	HSURFACE surface = wl_compositor_create_surface(wlGetCompositor());
 
 	/* shell_surface具有移动、改变大小、设置标题、最大化、最小化等功能 */
 	HSHELLSURFACE shell_surface = wl_shell_get_shell_surface(wlGetShell(), surface);

 
 	/* 窗口的私有数据 */
 	LPSURFACEPRIVATE surface_priv = (LPSURFACEPRIVATE)malloc(sizeof(SURFACEPRIVATE));
 	memset(surface_priv, 0, sizeof(SURFACEPRIVATE));
 
 	surface_priv->hSurface = surface;
 	surface_priv->hShell = shell_surface;
 	surface_priv->sz.width = width;
 	surface_priv->sz.height = height;

	wl_surface_set_user_data(surface, surface_priv);
 
 	/* 设置响应函数 */
 	wl_shell_surface_add_listener(shell_surface, &shell_surface_listener, NULL);
 	wl_shell_surface_set_title(shell_surface, title);
 	wl_shell_surface_set_toplevel(shell_surface);
 	wl_surface_damage(surface, 0, 0, width, height);
 
 	return surface;
 }

 // 
// void frame_listener_done(void *data, HCALLBACK callback, uint32_t time)
// {
// 	HSURFACE surface = (HSURFACE)data;
// 
// 	if( NULL != wlGetSurfacePrivate(surface)->lpfnPaintDone )
// 	{
// 		wlGetSurfacePrivate(surface)->lpfnPaintDone(surface);
// 	}
// }
// 
// static struct wl_callback_listener frame_listener = {
// 	.done = frame_listener_done
// };
// 
// void wlRequestPaintDone(HSURFACE surface)
// {
// 	HCALLBACK callback = wl_surface_frame(surface);
// 	wl_callback_add_listener(callback, &frame_listener, surface);
// }
// 
// int wlShowSurface(HSURFACE surface)
// {
// 	wlCallPaintProc(surface);
// 	return 1;
// }
// 
// void buffer_release(void *data, struct wl_buffer *buffer)
// {
// 	LPPAINTBUFFER lpBuffer = (LPPAINTBUFFER)data;
// 	lpBuffer->bBusy = 0;
// }
// 
// static const struct wl_buffer_listener buffer_listener = {
// 	.release = buffer_release
// };
// 
// int os_create_anonymous_file(int length)
// {
// 	char filename[] = "/tmp/weston-shared-XXXXXX";
// 	int fd = mkstemp(filename);
// 	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
// 	unlink(filename);
// 	ftruncate(fd, length);
// 	return fd;
// }
// 
// static void CreatePaintBuffer(int width, int height, LPPAINTBUFFER lpBuffer)
// {
// 	cairo_format_t cairo_format = CAIRO_FORMAT_ARGB32;
// 	int stride = cairo_format_stride_for_width (cairo_format, width);
// 	int size = stride * height;
// 	int fd = os_create_anonymous_file(size);
// 
// 	lpBuffer->lpPixelBuffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// 	//lpBuffer->data == MAP_FAILED
// 	
// 	HSHMPOOL pool = wl_shm_create_pool(wlGetRegistry()->s_shm, fd, size);
// 	lpBuffer->hBuffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, WL_SHM_FORMAT_XRGB8888);
// 	wl_buffer_add_listener(lpBuffer->hBuffer, &buffer_listener, lpBuffer);
// 	wl_shm_pool_destroy(pool);
// 	close(fd);
// 
// 	HCAIROSURFACE hCairoSurface;
// 	hCairoSurface = cairo_image_surface_create_for_data((unsigned char*)lpBuffer->lpPixelBuffer, cairo_format, width, height, stride);
// 
// 	lpBuffer->bBusy = 0;
// 	lpBuffer->hCairoSurface = hCairoSurface;
// 	lpBuffer->stride = stride;
// 	lpBuffer->length = size;
// }
// 
// void wlBeginPaint(HSURFACE surface, LPPAINTSTRUCTURE lpPaint)
// {
// 	LPSURFACEPRIVATE _priv = wlGetSurfacePrivate(surface);
// 	if (!_priv->buffer[0].bBusy && _priv->buffer[0].hBuffer)
// 	{
// 		lpPaint->lpBuffer = &_priv->buffer[0];
// 	}
// 	else if (!_priv->buffer[1].bBusy && _priv->buffer[1].hBuffer)
// 	{
// 		lpPaint->lpBuffer = &_priv->buffer[1];
// 	}
// 	else
// 	{
// 		SIZE sz = wlGetSurfaceSize(surface);
// 		CreatePaintBuffer(sz.width, sz.height, &_priv->buffer[0]);
// 		lpPaint->lpBuffer = &_priv->buffer[0];
// 	}
// }
// 
// void wlEndPaint(HSURFACE surface, LPPAINTSTRUCTURE lpPaint)
// {
// 	lpPaint->lpBuffer->bBusy = 1;
// 	wl_surface_attach(surface, lpPaint->lpBuffer->hBuffer, 0, 0);
// 	SIZE sz = wlGetSurfaceSize(surface);
// 	wl_surface_damage(surface, 0, 0, sz.width, sz.height);
// 	wl_surface_commit(surface);
// }
// 
// SIZE wlGetSurfaceSize(HSURFACE surface) {
// 	return wlGetSurfacePrivate(surface)->sz;
// }
// 
// LPWAYLANDREGISTRY wlGetRegistry()
// {
// 	static WAYLANDREGISTRY registry;
// 	static int bInit = 1;
// 	if (bInit)
// 	{
// 		memset(&registry, 0, sizeof(registry));
// 		bInit = 0;
// 	}
// 
// 	return &registry;
// }
